﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Windows.Storage;
using System.Threading;

namespace mBook.DataManager
{
    public class ProgressStream : Stream
    {

        private StorageFile _file;
        private long _RWCount = 0;
        private long _writeLength = 0;
        private CancellationTokenSource _cancellationTokenSource;

        public delegate void ProgressHandler(object sender, int Progress, long Transfered, long Length, StorageFile file);
        public event ProgressHandler Progress;
        private void UpdateProgress(int ProgressPercentage, long Transfered, long Length, StorageFile file)
        {
            ProgressHandler handler = Progress;
            if (handler != null)
            {
                // Invokes the delegates.
                handler(this, ProgressPercentage, Transfered, Length, file);
            }
        }


        private Stream _baseStream;
        public ProgressStream(Stream baseStream, StorageFile file)
        {
            _baseStream = baseStream;
            _file = file;
        }
        public ProgressStream(Stream baseStream, StorageFile file, long writeLength)
        {
            _baseStream = baseStream;
            _file = file;
            _writeLength = writeLength;
        }

        public ProgressStream(Stream baseStream, StorageFile file, CancellationTokenSource cancellationTokenSource)
        {
            _baseStream = baseStream;
            _file = file;
            _cancellationTokenSource = cancellationTokenSource;
        }

        public ProgressStream(Stream baseStream, StorageFile file, long writeLength, CancellationTokenSource cancellationTokenSource)
        {
            _baseStream = baseStream;
            _file = file;
            _writeLength = writeLength;
            _cancellationTokenSource = cancellationTokenSource;
        }


        public override bool CanRead
        {
            get { return _baseStream.CanRead; }
        }

        public override bool CanSeek
        {
            get { return _baseStream.CanSeek; }
        }

        public override bool CanWrite
        {
            get { return _baseStream.CanWrite; }
        }

        public override void Flush()
        {
            _baseStream.Flush();
        }

        public override long Length
        {
            get { return _baseStream.Length; }
        }

        public override long Position
        {
            get
            {
                return _baseStream.Position;
            }
            set
            {
                _baseStream.Position = value;
            }
        }

        public override long Seek(long offset, SeekOrigin origin)
        {
            return _baseStream.Seek(offset, origin);
        }

        public override void SetLength(long value)
        {
            _baseStream.SetLength(value);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public override int Read(byte[] buffer, int offset, int count)
        {
            if (_cancellationTokenSource != null && _cancellationTokenSource.IsCancellationRequested) throw new TaskCanceledException();


            int read = _baseStream.Read(buffer, offset, count);

            _RWCount += read;
            int percent = (int)(_RWCount * 100 / _baseStream.Length);
            UpdateProgress(percent, _RWCount, _baseStream.Length, _file);

            return read;
        }

        /// <summary>
        /// Additional event thrown with progress. Note we have to supply the file length to the constructor as the stream doesn't know up front
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        public override void Write(byte[] buffer, int offset, int count)
        {
            if (_cancellationTokenSource != null && _cancellationTokenSource.IsCancellationRequested) throw new TaskCanceledException();


            _baseStream.Write(buffer, offset, count);

            if (_writeLength > 0)
            {
                //throw new Exception("Total file length required by constructor when writing stream");
                _RWCount += count;
                int percent = (int)(_RWCount * 100 / _writeLength);
                UpdateProgress(percent, _RWCount, _writeLength, _file);
            }
        }

        protected override void Dispose(bool disposing)
        {
            _baseStream.Dispose();
            base.Dispose(disposing);
        }


    }
}
